<dialog>とPreactでmodal windowを作ってみる
背景
focus制御やクリック判定などに悩まされないで済む?
2023-08-23
17:50:08 custom hooksに切り出してみる
code:app2.tsx
/// <reference no-default-lib="true" />
/// <reference lib="esnext" />
/// <reference lib="dom" />
/** @jsx h */
/** @jsxFrag Fragment */
import { Fragment, h, render } from "../preact/mod.tsx";
import { useCallback, useState, useMemo, useEffect, useRef } from "../preact/hooks.ts";
const useDialog = () => {
const ref = useRef<HTMLDialogElement>(null);
const open = useCallback(() => ref.current?.showModal?.(), []);
const close = useCallback(() => ref.current?.close?.(), []);
return { ref, open, close, isOpen: ref.current?.open ?? false };
};
const App = () => {
const { ref, open, close } = useDialog();
/** dialogクリックではmodalを閉じないようにする */
const stopPropagation = useCallback((e: Event) => e.stopPropagation(), []);
return (<>
<style>{`
body:has(dialog:modal) {
touch-action: none;
overflow: hidden;
overscroll-behavior: none;
}
button.open {
position: fixed;
z-index: 1050;
top: 10%;
left: 10%;
}
dialog {
background: red;
}
`}</style>
<button className="open" onClick={open}>open modal</button>
<dialog ref={ref} onClick={close}>
<div className="container" onClick={stopPropagation}>
<p>dialog内のテキスト</p>
<button className="close" onClick={close}>close</button>
</div>
</dialog>
</>)
};
const app = document.createElement("div");
const shadowRoot = app.attachShadow({ mode: "open" });
document.body.append(app);
render(<App />, shadowRoot);
code:css
body:has(dialog:modal) {
touch-action: none;
overflow: hidden;
overscroll-behavior: none;
}
17:35:36 うーん、スクロールがロックされないぞ?
shadowDOMをやめても同じだった
code:app.tsx
/// <reference no-default-lib="true" />
/// <reference lib="esnext" />
/// <reference lib="dom" />
/** @jsx h */
/** @jsxFrag Fragment */
import { Fragment, h, render } from "../preact/mod.tsx";
import { useCallback, useState, useMemo, useEffect, useRef } from "../preact/hooks.ts";
const App = () => {
const ref = useRef<HTMLDialogElement>(null);
const open = useCallback(() => ref.current?.showModal?.(), []);
const close = useCallback(() => ref.current?.close?.(), []);
/** dialogクリックではmodalを閉じないようにする */
const stopPropagation = useCallback((e: Event) => e.stopPropagation(), []);
return (<>
<style>{`
body:has(dialog:modal) {
touch-action: none;
overflow: hidden;
overscroll-behavior: none;
}
button.open {
position: fixed;
z-index: 1050;
top: 10%;
left: 10%;
}
`}</style>
<button className="open" onClick={open}>open modal</button>
<dialog ref={ref} onClick={close}>
<div className="container" onClick={stopPropagation}>
<p>dialog内のテキスト</p>
<button className="close" onClick={close}>close</button>
</div>
</dialog>
</>)
};
const app = document.createElement("div");
const shadowRoot = app.attachShadow({ mode: "open" });
document.body.append(app);
render(<App />, shadowRoot);